package happy.diandiankong.api.client;

import happy.diandiankong.api.exception.ApiServerException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * Title.
 * <p/>
 * Description.
 *
 * @author Bill Lv {@literal <billcc.lv@hotmail.com>}
 * @version 1.0
 * @since 2015-09-14
 */
public abstract class BaseClient {
    static final Logger LOGGER = LoggerFactory.getLogger(BaseClient.class);

    protected static final String CONTENT_TYPE_JSON = "application/json";
    protected static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";

    protected static final String X_AUTH_USERNAME = "X-Auth-Username";
    protected static final String X_AUTH_PASSWORD = "X-Auth-Password";
    protected static final String X_AUTH_TOKEN = "X-Auth-Token";
    protected static final String AUTHORIZATION = "Authorization";

    protected abstract CloseableHttpClient createClient();

    protected abstract String getUserAgent();

    protected abstract String getContentType();

    protected abstract Map<String, String> getAuthHeaders();

    public String get(String url) throws IOException, ApiServerException {
        HttpGet request = new HttpGet(url);
        request.setHeader("User-Agent", getUserAgent());
        request.setHeader("accept", getContentType());
        if (getAuthHeaders() != null) {
            for (String key : getAuthHeaders().keySet()) {
                request.setHeader(key, getAuthHeaders().get(key));
            }
        }

        return service(request);
    }

    public String post(String url) throws IOException, ApiServerException {
        return post(url, null);
    }

    public String post(String url, String input) throws IOException, ApiServerException {
        HttpPost request = new HttpPost(url);
        request.setHeader("User-Agent", getUserAgent());
        request.setHeader("Content-Type", getContentType());
        if (getAuthHeaders() != null) {
            for (String key : getAuthHeaders().keySet()) {
                request.setHeader(key, getAuthHeaders().get(key));
            }
        }

        if (StringUtils.isNotBlank(input)) {
            StringEntity stringEntity = new StringEntity(input, Consts.UTF_8);
            stringEntity.setContentType(getContentType());
            request.setEntity(stringEntity);
        }

        return service(request);
    }

    protected String postFile(String url, String payload, File file) throws IOException, ApiServerException {
        HttpPost request = new HttpPost(url);
        request.setHeader("User-Agent", getUserAgent());
        request.setHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryf6LDyP9jaAlS571g");
        if (getAuthHeaders() != null) {
            for (String key : getAuthHeaders().keySet()) {
                request.setHeader(key, getAuthHeaders().get(key));
            }
        }

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

        builder.addBinaryBody
                (payload, file, ContentType.create("image/jpeg"), file.getName());
        builder.setLaxMode().setBoundary("----WebKitFormBoundaryf6LDyP9jaAlS571g").setCharset(Charset.forName("UTF-8"));

        request.setEntity(builder.build());

        return service(request);
    }

    private String service(HttpRequestBase request) throws IOException, ApiServerException {
        CloseableHttpClient client = null;
        try {
            client = createClient();
            HttpResponse response = client.execute(request);
            InputStream input = null;
            try {
                input = response.getEntity().getContent();
                String content = IOUtils.toString(input, Consts.UTF_8);
                LOGGER.info("response content: {}", content);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200 || statusCode == 201 || statusCode == 226
                        || statusCode == 406 || statusCode == 424) {
                    return content;
                }
                throw new ApiServerException(content);
            } catch (IOException e) {
                LOGGER.error("", e);
                throw new RuntimeException(e);
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        LOGGER.error("", e);
                        throw new RuntimeException(e);
                    }
                }
            }
        } finally {
            if (request != null) {
                request.releaseConnection();
            }
            if (client != null) {
                client.close();
            }
        }
    }
}
